﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using StyleMVVM.Data;
using StyleMVVM.DataService.DotNet.Messages;
using StyleMVVM.DependencyInjection;

namespace StyleMVVM.DataService.DotNet.Service
{
	public class DataAccessService : IDataAccessService
	{
		private static ConcurrentDictionary<string, Type> crudInterfaceTypes = new ConcurrentDictionary<string, Type>();
		private static ConcurrentDictionary<string, Type> messageInterfaceTypes = new ConcurrentDictionary<string, Type>();

		private IDependencyInjectionContainer container;

		public DataAccessService(IDependencyInjectionContainer container)
		{
			this.container = container;
		}

		public DataAccessGetResponse GetData(DataAccessGetRequest request)
		{
			string crudKey = request.DataKeyType.ToString() + "|" + request.DataType;
			Type interfaceType;

			if (!crudInterfaceTypes.TryGetValue(crudKey, out interfaceType))
			{
				List<Tuple<string, Type>> types = FindTypeByName(request.DataType);

				if (types.Count != 1)
				{
					throw new Exception("Could not find type: " + request.DataType);
				}

				Type keyType = typeof(int);

				switch (request.DataKeyType)
				{
					case DataKeyType.Int:
						keyType = typeof(int);
						break;

					case DataKeyType.Guid:
						keyType = typeof(Guid);
						break;

					case DataKeyType.String:
						keyType = typeof(string);
						break;
				}

				interfaceType = typeof(IDataAccessAdapter<,>).MakeGenericType(keyType, types[0].Item2);

				crudInterfaceTypes[crudKey] = interfaceType;
			}

			container.LocateByType(interfaceType);

			DataAccessGetResponse response = new DataAccessGetResponse();

			return response;
		}

		public DataAccessMessageResponse SendMessage(DataAccessMessageRequest request)
		{
			throw new NotImplementedException();
		}


		protected virtual List<Tuple<string, Type>> FindTypeByName(params string[] names)
		{
			List<Tuple<string, Type>> returnList = new List<Tuple<string, Type>>();

			foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
			{
				foreach (Type exportedType in assembly.ExportedTypes)
				{
					string foundName = names.FirstOrDefault(x => x == exportedType.FullName);

					if (!string.IsNullOrEmpty(foundName))
					{
						returnList.Add(new Tuple<string, Type>(foundName, exportedType));

						if (returnList.Count == names.Length)
						{
							break;
						}
					}
				}
			}

			return returnList;
		}
	}
}